#pragma once
#include<iostream>
#include<vector>
#include<queue>
#include<pthread.h>
#include"Log.hpp"
#include"Thread.hpp"
#include"LockGuard.hpp"
using namespace ThreadModule;

const static int gdefuaultthreadnum=5;//默认线程5个

//函数模板 
template<typename T>
class ThreadPool
{
    private:
    void LockQueue()//队列锁
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()//解锁
    {
        pthread_mutex_unlock(&_mutex);
    }

    void ThreadSleep()//等待线程
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    void ThreadWakeup()//唤醒线程
    {
        //发送信号
        pthread_cond_signal(&_cond);
    }
    void ThreadWakeAll()
    {
        //唤醒全部线程
        pthread_cond_broadcast(&_cond);
    }
    //构造
    ThreadPool(int threadnum = gdefuaultthreadnum)
    :_thraednum(threadnum)
    ,_waitnum(0)
    ,_isrunning(false)
    {
        //初始化和锁线程
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
        LOG(INFO,"ThreadPool Construct()");
    }
    void InitThreadPool()//初始化线程池
    {
        //构架除所有线程，不启动
        for(int num = 0;num<_thraednum;num++)
        {
             std::string name ="thread-"+std::to_string(num+1);
             _threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1),name);
             LOG(INFO,"init thread %s done\n",name.c_str());
        }
        _isrunning = true;
    }
    void Start()//启动
    {
        for(auto &thread:_threads)
        {
            thread.Start();
        }
    }
    void HandlerTask(std::string name)//处理任务 房版继续类级别的相互调用
    {
        LOG(INFO,"%s is running...\n",name.c_str());
        //保证队列安全先调用队列锁
        while(true)
        {
            LockQueue();
            //队列中是否有数据
            while (_task_queue.empty()&&_isrunning)
            {
                _waitnum++;
                ThreadSleep();
                _waitnum--;
            }
            //2:线程池退出，任务队列是空
            if(_task_queue.empty()&&!_isrunning)
            {
                //解锁队列
                UnlockQueue();
                break;;
            }
            //线程池不退出，任务队列不是空
            //线程池退出，任务队列不为空，处理完任务之后退出；
            T t = _task_queue.front();
            _task_queue.pop();
            UnlockQueue();
            LOG(DEBUG,"%s get a task",name.c_str());
            t();//处理任务，任务数据线程独占的任务；
        }
    }
    //禁用拷贝构造和赋值
    ThreadPool<T>&operator=(const ThreadPool<T> &) = delete;
    ThreadPool(const ThreadPool<T> &) = delete;

    public:
  
    static ThreadPool<T> *GetInstance()
    {
        //只有第一次会创建对象，后续都是获取
        //双判断的方式，可以有效减少获取单列的枷锁成本，保证线程安全
        if(nullptr==_instance)
        {
            LockGuard lockguanr(&_lock);
            if(nullptr==_instance)
            {
                _instance = new ThreadPool<T>();
                _instance->InitThreadPool();
                _instance->Start();
                LOG(DEBUG,"创建线程池单例\n");
                return _instance;
            }
        }
        LOG(DEBUG,"获取线程单例\n");
        return _instance;
    }
    void Stop()
    {
        LockQueue();
        _isrunning = false;
        ThreadWakeAll();
        UnlockQueue();
    }
    void Wait()//等待
    {
        for(auto &thread:_threads)
        {
            thread.join();
            LOG(INFO,"%s is quit...",thread.name().c_str());
        }
    }
    bool Enqueue(const T &t)//入队列
    {
        bool ret = false;
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(t);
            if(_waitnum>0)//等待信号
            {
                //唤醒线程
                ThreadWakeup();
            }
            LOG(DEBUG,"enqueue task succsee\n");
            ret = true;
        }
        UnlockQueue();
        return ret;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    private:
    int _thraednum ;//线程数量
    std::vector<Thread> _threads;//多线程
    std::queue<T> _task_queue;//处理任务队列
    
    pthread_mutex_t _mutex;//锁
    pthread_cond_t _cond;//同步
    
    int _waitnum;//等待编号
    bool _isrunning;//运行状态

    //单例模式
    static ThreadPool<T> *_instance;
    static pthread_mutex_t _lock;
};
template<typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;
template<typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;
